/*
  Part of the MasterTool3D project - http://code.google.com/p/master-tool-3d

  Copyright (c) 2011 Ingo Pueschl

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation, version 2.1.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package techjit.gfx.util;

import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PMatrix3D;
import techjit.gfx.core.P;
import techjit.gfx.util.geo.Vector;
import techjit.util.RuntimeParams;

public class PU {

	// FIELDS
	private static boolean showTranslationTrace = false;

	// METHODS
	public static void trapezoid(PApplet p, Vector v1, Vector v2) {

		float x1 = v1.getX();
		float y1 = v1.getY();
		float z1 = v1.getZ();

		float x2 = v2.getX();
		float y2 = v2.getY();
		float z2 = v2.getZ();

		p.beginShape();
		{
			p.vertex(0, 0, 0);
			p.vertex(x1, y1, z1);
			p.vertex(x1 + x2, y1 + y2, z1 + z2);
			p.vertex(x2, y2, z2);
		}
		p.endShape(P.CLOSE);
	}

	public static void trapezoid(PApplet p, Vector v0, Vector v1, Vector v2) {
		p.pushMatrix();
		{
			PU.translate(p, v0);
			PU.trapezoid(p, v1, v2);
		}
		p.popMatrix();
	}

	public static void box(PApplet p, Vector v111) {

		float x = v111.getX();
		float y = v111.getY();
		float z = v111.getZ();

		p.pushMatrix();
		{
			PU.translate(p, new Vector(x / 2, y / 2, z / 2));
			p.box(x, y, z);
		}
		p.popMatrix();

	}

	public static void box(PApplet p, Vector v000, Vector v111) {
		v111.subtract(v000);
		p.pushMatrix();
		{
			PU.translate(p, v000);
			PU.box(p, v111);
		}
		p.popMatrix();
	}

	public static float cos(float alpha) {
		return PApplet.cos(PApplet.radians(alpha));
	}

	public static void diamond(PApplet p, Vector v111) {
		// x, y, z
		float x = v111.getX();
		float y = v111.getY();
		float z = v111.getZ();

		// half x, y, z
		float hX = x / 2;
		float hY = y / 2;
		float hZ = z / 2;

		// draw diamond x-y-plane
		PU.line(p, new Vector(hX, 0, hZ), new Vector(0, hY, hZ));
		PU.line(p, new Vector(0, hY, hZ), new Vector(hX, y, hZ));
		PU.line(p, new Vector(hX, y, hZ), new Vector(x, hY, hZ));
		PU.line(p, new Vector(x, hY, hZ), new Vector(hX, 0, hZ));

		// draw diamond x-z-plane
		PU.line(p, new Vector(hX, hY, 0), new Vector(0, hY, hZ));
		PU.line(p, new Vector(0, hY, hZ), new Vector(hX, hY, z));
		PU.line(p, new Vector(hX, hY, z), new Vector(x, hY, hZ));
		PU.line(p, new Vector(x, hY, hZ), new Vector(hX, hY, 0));

		// draw diamon y-z-plane
		PU.line(p, new Vector(hX, hY, 0), new Vector(hX, y, hZ));
		PU.line(p, new Vector(hX, y, hZ), new Vector(hX, hY, z));
		PU.line(p, new Vector(hX, hY, z), new Vector(hX, 0, hZ));
		PU.line(p, new Vector(hX, 0, hZ), new Vector(hX, hY, 0));
	}

	public static void ellipse(PApplet p, Vector v111) {

		float x = v111.getX();
		float y = v111.getY();
		float z = v111.getZ();

		if (y == 0) {
			p.pushMatrix();
			{
				p.ellipseMode(PConstants.CORNER);
				PU.rotateX(p, 90);
				p.ellipse(0, 0, x, z);
			}
			p.popMatrix();
		}
	}

	public static PMatrix3D getRotationMatrixX(float angle) {
		float sinAngle = PApplet.sin(PApplet.radians(angle));
		float cosAngle = PApplet.cos(PApplet.radians(angle));

		PMatrix3D rotMatrixX = new PMatrix3D(1, 0, 0, 0, 0, cosAngle,
				-sinAngle, 0, 0, sinAngle, cosAngle, 0, 0, 0, 0, 1);
		return rotMatrixX;
	}

	public static PMatrix3D getRotationMatrixY(float angle) {
		float sinAngle = PApplet.sin(PApplet.radians(angle));
		float cosAngle = PApplet.cos(PApplet.radians(angle));

		PMatrix3D rotMatrixY = new PMatrix3D(cosAngle, 0, sinAngle, 0, 0, 1, 0,
				0, -sinAngle, 0, cosAngle, 0, 0, 0, 0, 1);
		return rotMatrixY;
	}

	public static PMatrix3D getRotationMatrixZ(float angle) {
		float sinAngle = PApplet.sin(PApplet.radians(angle));
		float cosAngle = PApplet.cos(PApplet.radians(angle));

		PMatrix3D rotMatrixZ = new PMatrix3D(cosAngle, -sinAngle, 0, 0,
				sinAngle, cosAngle, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
		return rotMatrixZ;
	}

	public static void line(PApplet p, Vector v1, Vector v2) {
		p.line(v1.getX(), v1.getY(), v1.getZ(), v2.getX(), v2.getY(), v2.getZ());
	}

	public static void marker(PApplet p) {
		float markerDimension = 1;
		float f = markerDimension / 2;
		p.pushStyle();
		{
			p.noFill();
			PU.line(p, new Vector(-f), new Vector(f));
			PU.line(p, new Vector(f, -f, -f), new Vector(-f, f, f));
			PU.line(p, new Vector(-f, f, -f), new Vector(f, -f, f));
			PU.line(p, new Vector(-f, -f, f), new Vector(f, f, -f));
			PU.box(p, new Vector(-f), new Vector(f));
		}
		p.popStyle();
	}

	public static Vector model(PApplet p) {
		float x = p.modelX(0, 0, 0);
		float y = p.modelY(0, 0, 0);
		float z = p.modelZ(0, 0, 0);

		return new Vector(x, y, z);
	}

	public static void rotateX(PApplet p, float angle) {
		p.rotateX(PApplet.radians(angle));
	}

	public static void rotateY(PApplet p, float angle) {
		p.rotateY(PApplet.radians(angle));
	}

	public static void rotateZ(PApplet p, float angle) {
		p.rotateZ(PApplet.radians(angle));
	}

	public static float sin(float alpha) {
		return PApplet.sin(PApplet.radians(alpha));
	}

	/* Draws a sphere with specified radius with the current matrix as midpoint. */
	public static void sphere(PApplet p, float radius) {
		p.sphere(radius);
	}

	/* Draws a sphere with specified radius at midPoint vector. */
	public static void sphere(PApplet p, float radius, Vector midPoint) {
		float x = midPoint.getX();
		float y = midPoint.getY();
		float z = midPoint.getZ();
		Vector delta = new Vector(x, y, z);
		p.pushMatrix();
		{
			PU.translate(p, delta);
			PU.sphere(p, radius);
		}
		p.popMatrix();
	}

	/*
	 * Draws a sphere inside the bounding box specified by the v111 vector with
	 * current matrix as 000 vector.
	 */
	public static void sphere(PApplet p, Vector v111) {
		float x = v111.getX();
		float y = v111.getY();
		float z = v111.getZ();
		Vector delta = new Vector(x / 2, y / 2, z / 2);
		p.pushMatrix();
		{
			PU.translate(p, delta);
			PU.sphere(p, x / 2);
		}
		p.popMatrix();
	}

	/*
	 * Draws a sphere inside the bounding box specified by the v000 and v111
	 * vector based on current matrix.
	 */
	public static void sphere(PApplet p, Vector v000, Vector v111) {
		v111.subtract(v000);
		p.pushMatrix();
		{
			PU.translate(p, v000);
			PU.sphere(p, v111);
		}
		p.popMatrix();
	}

	// public static void sphere(PApplet p, Vector v, float radius) {
	// p.pushMatrix();
	// {
	// PU.translate(p, v);
	// p.sphere(radius );
	// }
	// p.popMatrix();
	// }
	//
	// public static void sphere(PApplet p, Vector v111) {
	// p.pushMatrix();
	// {
	// Vector delta = new Vector(v111.getX() / 2, v111.getY() / 2,
	// v111.getZ() / 2);
	// float radius = delta.getX();
	// PU.translate(p, delta);
	// p.sphere(radius );
	// }
	// p.popMatrix();
	// }

	public static void strokeAndFill(PApplet p, int color) {
		p.stroke(color);
		p.fill(color);
	}

	public static String toString_model(PApplet p) {
		float x = p.modelX(0, 0, 0);
		float y = p.modelY(0, 0, 0);
		float z = p.modelZ(0, 0, 0);

		return x + "|" + y + "|" + z;
	}

	// public static void vector(PApplet p, Vector v111, float length) {
	// float x = v111.getX();
	// float y = v111.getY();
	// float z = v111.getZ();
	//
	// p.pushMatrix();
	// {
	// // PU.translate(p, new Vector(x / 2, y / 2, z / 2));
	// // p.box(x , y , z );
	// CoordinateSystemDrawer.drawAxis(p, 0, length);
	// }
	// p.popMatrix();
	//
	// }

	public static String toString_screen(PApplet p) {
		float x = p.screenX(0, 0, 0);
		float y = p.screenY(0, 0, 0);
		float z = p.screenZ(0, 0, 0);

		return x + "|" + y + "|" + z;
	}

	public static void translate(PApplet p, Vector v) {
		if (showTranslationTrace) {
			p.pushStyle();
			{
				p.stroke(RuntimeParams.COLOR__CYAN);
				PU.line(p, new Vector(0), v);
			}
			p.popStyle();
		}
		p.translate(v.getX(), v.getY(), v.getZ());
	}

	public static void translate_activateTrace() {
		if (RuntimeParams.SHOW__CIRCLE_LAYOUT_TRACE) {
			showTranslationTrace = true;
		}
	}

	public static void translate_deactivateTrace() {
		showTranslationTrace = false;
	}

	public static void vertex(PApplet p, Vector v) {
		p.vertex(v.getX(), v.getY(), v.getZ());
	}
}
